#include "tan_boolobject.h"
#include "tan_alloc.h"

static const TAN_INT8* bool_object_name = "string";
#define Tan_isBool(ob)	TanCompareTypeString(ob, bool_object_name)
#define Tan_BoolObject_cast(ob) ((TanBoolObject*)(ob))

TanObject* Tan_Bool_Copy(TanObject* _bool)
{
	TanBoolObject* _bool_object = 0;
	if (strcmp(_bool->object_type, "bool") != 0) return Tan_Object_cast(_bool_object);

	_bool_object = (TanBoolObject*)Tan_AllocObject_Memset(sizeof(TanBoolObject));
	_bool_object->_bool = Tan_BoolObject_cast(_bool)->_bool;
	Tan_Object_cast(_bool_object)->object_type = bool_object_name;
	Tan_Object_cast(_bool_object)->object_set = Tan_Object_cast(_bool)->object_set;
	Tan_Var_cast(_bool_object)->var_req = 1;
	Tan_Var_cast(_bool_object)->var_size = 1;
	return Tan_Object_cast(_bool_object);
}

static void bool_delete(TanObject* oneself)
{
	if (Tan_isBool(oneself))
	{
		free(Tan_BoolObject_cast(oneself));
	}
}

static void	bool_clear(TanObject* oneself)
{
	if (Tan_isBool(oneself))
	{
		Tan_BoolObject_cast(oneself)->_bool = false;

		Tan_Var_cast(oneself)->var_req = 1;
		Tan_Var_cast(oneself)->var_size = 0;
	}
}

static void bool_repr(TanObject* oneself)
{
	if (Tan_isBool(oneself))
	{
		if (Tan_BoolObject_cast(oneself)->_bool == true)
		{
			printf("true");
		}
		else if (Tan_BoolObject_cast(oneself)->_bool == false)
		{
			printf("false");
		} 
		else
		{
			Tan_RepError(0, "The boolean type has an incorrect value.", oneself);
		}
	}
	else Tan_RepError(0, "Not of type 'bool'", oneself);
}

static Tan_bool bool_compare(TanObject* oneself, TanObject* other, TanCompareType type)
{
	if (!Tan_isBool(oneself)) { Tan_RepError(0, "Not is boolean.", oneself); return Tan_false; }
	if (!Tan_isBool(other)) { Tan_RepError(0, "This operation cannot be performed on type 'bool'.", other); return Tan_false; }

	if (type == Tan_compare_equal)
	{
		if (Tan_BoolObject_cast(oneself)->_bool == Tan_BoolObject_cast(other)->_bool)
			return Tan_true;
		else return Tan_false;
	}
	else if (type == Tan_compare_noequal)
	{
		if (Tan_BoolObject_cast(oneself)->_bool != Tan_BoolObject_cast(other)->_bool)
			return Tan_true;
		else return Tan_false;
	}
	else if (type == Tan_compare_greaterThan)
	{
		if (Tan_BoolObject_cast(oneself)->_bool > Tan_BoolObject_cast(other)->_bool)
			return Tan_true;
		else return Tan_false;
	}
	else if (type == Tan_compare_lessThan)
	{
		if (Tan_BoolObject_cast(oneself)->_bool < Tan_BoolObject_cast(other)->_bool)
			return Tan_true;
		else return Tan_false;
	}
	else if (type == Tan_compare_grea_equal)
	{
		if (Tan_BoolObject_cast(oneself)->_bool >= Tan_BoolObject_cast(other)->_bool)
			return Tan_true;
		else return Tan_false;
	}
	else if (type == Tan_compare_less_equal)
	{
		if (Tan_BoolObject_cast(oneself)->_bool <= Tan_BoolObject_cast(other)->_bool)
			return Tan_true;
		else return Tan_false;
	}
	else 
	{
		Tan_RepError(0, "The two types cannot be compared.", oneself);
		return Tan_false;
	}
	Tan_RepError(1, "successful.", oneself);

	return Tan_true;
}

void bool_assign(TanObject** oneself, TanObject* other, TanAssignType type)
{
	if (!Tan_isBool(*oneself)) { Tan_RepError(0, "Not is boolean.", *oneself); return; }
	if (!Tan_isBool(other)) { Tan_RepError(0, "This operation cannot be performed on type 'bool'.", other); return; }

	if (type == Tan_assign_equal)
	{
		Tan_BoolObject_cast(*oneself)->_bool = Tan_BoolObject_cast(other)->_bool;
	}
	else
	{
		Tan_RepError(0, "This operator cannot be executed.", *oneself);
	}
}

TanObject* bool_opt(TanObject* oneself, TanObject* other, TanOperationType type)
{
	if (!Tan_isBool(oneself)) { Tan_RepError(0, "Not is boolean.", oneself); return 0; }
	if (!Tan_isBool(other)) { Tan_RepError(0, "This operation cannot be performed on type 'bool'.", other); return 0; }

	Tan_RepError(0, "'bool' type cannot be an operational expression", oneself);
	return Tan_Bool_fromString("false", 5);
}

static TanObjectType bool_object_Type =
{
	Tan_Bool_Copy,	// type_copy
	bool_delete,	// type_delete
	bool_clear,		// type_clear
	bool_repr,		// var_repr
	bool_compare,	// var_coompare
	bool_assign,	// var_assign
	bool_opt,		// var_operation
	0,
	0				// next
};

TanObject* Tan_Bool_fromString(const TAN_INT8* str, tan_size_t len)
{
	TanBoolObject* _bool_object = (TanBoolObject*)Tan_AllocObject_Memset(sizeof(TanBoolObject));
	tan_size_t _bool_len = len ? len : strlen(str);

	TAN_INT8* _bool_string = (TAN_INT8*)Tan_malloc(_bool_len + 1);
	if (_bool_string)
	{
		memset(_bool_string, 0, _bool_len + 1);
		memcpy(_bool_string, str, _bool_len);

		if (Tan_StrCmp(_bool_string, "true"))
		{
			_bool_object->_bool = true;
		}
		else if (Tan_StrCmp(_bool_string, "false"))
		{
			_bool_object->_bool = false;
		}
	} else tan_assert(_bool_object, "Out of memory space.");
	
	Tan_Object_cast(_bool_object)->object_type = bool_object_name;
	Tan_Object_cast(_bool_object)->object_set = &bool_object_Type;
	Tan_Var_cast(_bool_object)->var_req = 1;
	Tan_Var_cast(_bool_object)->var_size = 1;

	return Tan_Object_cast(_bool_object);
}

TanObject* Tan_Bool(const bool _bool)
{
	TanBoolObject* _bool_object = (TanBoolObject*)Tan_AllocObject_Memset(sizeof(TanBoolObject));
	_bool_object->_bool = _bool;
	Tan_Object_cast(_bool_object)->object_type = bool_object_name;
	Tan_Object_cast(_bool_object)->object_set = &bool_object_Type;
	Tan_Var_cast(_bool_object)->var_req = 1;
	Tan_Var_cast(_bool_object)->var_size = 1;
	return Tan_Object_cast(_bool_object);
}


